/*
 * chip_dma.c
 *
 *  Created on: 2011/07/18
 *      Author: AKS
 */

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>

#include "core/include/aks_processor.h"
#include "core/include/process.h"
#include "core/include/types.h"

#include "include/chip_dma.h"
#include "../include/memory.h"

static DMA_FINISHED_CALLBACK finished;

BOOL DMA_is_Free(void)
{
    return (DMA.STATUS & 0x10) ? FALSE : TRUE;
}

void DMA_Enabe(void)
{
	DMA.CTRL |= DMA_ENABLE_bm;
	DMA.CH0.CTRLA |= DMA_CH_ENABLE_bm;

    return;
}

void DMA_Disable(void)
{
	DMA.CH0.CTRLA &= ~DMA_CH_ENABLE_bm;
	DMA.CTRL &= ~DMA_ENABLE_bm;

    return;
}

void DMA_startTransmit(void)
{
	DMA.CH0.CTRLB |= DMA_CH_TRNINTLVL_gm;
	DMA.CH0.CTRLA |= DMA_CH_TRFREQ_bm;
    return;
}

BOOL DMA_setup(DWORD src, DWORD dst, WORD size, DMA_FINISHED_CALLBACK callback)
{
    volatile DMA_CH_t *dmaCh;
    dmaCh = &(DMA.CH0);

    // register callback
    finished = callback;

    // build dma channel
    /// set source address
    dmaCh->SRCADDR0 = (BYTE)((src>> 0) & 0xFF);
    dmaCh->SRCADDR1 = (BYTE)((src>> 8) & 0xFF);
    dmaCh->SRCADDR2 = (BYTE)((src>>16) & 0xFF);

    /// set destination address
    dmaCh->DESTADDR0 = (BYTE)((dst>> 0) & 0xFF);
    dmaCh->DESTADDR1 = (BYTE)((dst>> 8) & 0xFF);
    dmaCh->DESTADDR2 = (BYTE)((dst>>16) & 0xFF);

    /// set address control
    /// auto inc. src and dst
    dmaCh->ADDRCTRL = DMA_CH_SRCDIR_INC_gc | DMA_CH_DESTDIR_INC_gc;

    /// set load size
    dmaCh->TRFCNT = size;

    /// set dma control
    dmaCh->CTRLA = (dmaCh->CTRLA & ~(DMA_CH_BURSTLEN_gm | DMA_CH_REPEAT_bm)) | DMA_CH_BURSTLEN_2BYTE_gc;

    return TRUE;
}


ISR(DMA_CH0_vect)
{
	// fail to transmit.
	if (DMA.CH0.CTRLB & DMA_CH_ERRIF_bm) {
		DMA.CH0.CTRLB |= DMA_CH_ERRIF_bm;
		finished(FALSE);
	}
	// success to transmit
	else
	{
		DMA.CH0.CTRLB |= DMA_CH_TRNIF_bm;
		finished(TRUE);
	}

	return;
}
